module top # (
    parameter ADDR_WIDTH = 32,
    parameter DATA_WIDTH = 64,
    parameter MAKS_WIDTH = DATA_WIDTH / 8,

    parameter LINE_WIDTH    = 128,
    parameter STRB_WIDTH    = LINE_WIDTH / 8
) (
    input   logic                   clock,
    input   logic                   reset,

    // Interrupts
    input   logic                   msi, // from CLINT
    input   logic                   mti, // from CLINT

/* ********* AXI Master Interface ********* */
    // aw
    output  logic [3:0]             axi_awid,
    output  logic [ADDR_WIDTH-1:0]  axi_awaddr,
    output  logic [7:0]             axi_awlen,
    output  logic [2:0]             axi_awsize,
    output  logic [1:0]             axi_awburst,
    output  logic                   axi_awvalid,
    input   logic                   axi_awready,
    // w
    output  logic [DATA_WIDTH-1:0]  axi_wdata,
    output  logic [MAKS_WIDTH-1:0]  axi_wstrb,
    output  logic                   axi_wlast,
    output  logic                   axi_wvalid,
    input   logic                   axi_wready,
    // b
    input   logic [3:0]             axi_bid,
    input   logic [1:0]             axi_bresp,
    input   logic                   axi_bvalid,
    output  logic                   axi_bready,
    // ar
    output  logic [3:0]             axi_arid,
    output  logic [ADDR_WIDTH-1:0]  axi_araddr,
    output  logic [7:0]             axi_arlen,
    output  logic [2:0]             axi_arsize,
    output  logic [1:0]             axi_arburst,
    output  logic                   axi_arvalid,
    input   logic                   axi_arready,
    // r
    input   logic [3:0]             axi_rid,
    input   logic [DATA_WIDTH-1:0]  axi_rdata,
    input   logic [1:0]             axi_rresp,
    input   logic                   axi_rlast,
    input   logic                   axi_rvalid,
    output  logic                   axi_rready,
/* ********* AXI Master Interface ********* */

    output  logic [63:0]            debug_wb_pc,
    output  logic                   debug_wb_valid,

    // Commit
    output  logic [63:0]            icache_miss_count,
    output  logic [63:0]            dcache_miss_count,
    output  logic [63:0]            commit_inst_count,
    output  logic [63:0]            mmio_inst_count,
    output  logic [63:0]            mem_inst_count,
    output  logic                   commit_valid,
    output  logic [63:0]            commit_pc,
    output  logic [31:0]            commit_inst,
    output  logic                   commit_skip_ref
);

/* -------------------------------- Bridge -------------------------------- */
    // AXI Read
    logic                   inst_rd_req;
    logic [2:0]             inst_rd_type;
    logic [ADDR_WIDTH-1:0]  inst_rd_addr;
    logic                   inst_rd_rdy;
    logic                   inst_ret_valid;
    logic                   inst_ret_last;
    logic [LINE_WIDTH-1:0]  inst_ret_data;
    // AXI Write
    logic                   inst_wr_req;
    logic [2:0]             inst_wr_type;
    logic [ADDR_WIDTH-1:0]  inst_wr_addr;
    logic [STRB_WIDTH-1:0]  inst_wr_wstrb;
    logic [LINE_WIDTH-1:0]  inst_wr_data;
    logic                   inst_wr_rdy;
    // Fault
    logic                   inst_read_fault;
    logic                   inst_write_fault;

    // AXI Read
    logic                   data_rd_req;
    logic [2:0]             data_rd_type;
    logic [ADDR_WIDTH-1:0]  data_rd_addr;
    logic                   data_rd_rdy;
    logic                   data_ret_valid;
    logic                   data_ret_last;
    logic [LINE_WIDTH-1:0]  data_ret_data;
    // AXI Write
    logic                   data_wr_req;
    logic [2:0]             data_wr_type;
    logic [ADDR_WIDTH-1:0]  data_wr_addr;
    logic [STRB_WIDTH-1:0]  data_wr_wstrb;
    logic [LINE_WIDTH-1:0]  data_wr_data;
    logic                   data_wr_rdy;
    // Fault
    logic                   data_read_fault;
    logic                   data_write_fault;

    AXI4Bridge bridge (
        .clock              (clock),
        .reset              (reset),
    /* ********* AXI Master Interface ********* */
        // aw
        .axi_awid           (axi_awid),
        .axi_awaddr         (axi_awaddr),
        .axi_awlen          (axi_awlen),
        .axi_awsize         (axi_awsize),
        .axi_awburst        (axi_awburst),
        .axi_awvalid        (axi_awvalid),
        .axi_awready        (axi_awready),
        // w
        .axi_wdata          (axi_wdata),
        .axi_wstrb          (axi_wstrb),
        .axi_wlast          (axi_wlast),
        .axi_wvalid         (axi_wvalid),
        .axi_wready         (axi_wready),
        // b
        .axi_bid            (axi_bid),
        .axi_bresp          (axi_bresp),
        .axi_bvalid         (axi_bvalid),
        .axi_bready         (axi_bready),
        // ar
        .axi_arid           (axi_arid),
        .axi_araddr         (axi_araddr),
        .axi_arlen          (axi_arlen),
        .axi_arsize         (axi_arsize),
        .axi_arburst        (axi_arburst),
        .axi_arvalid        (axi_arvalid),
        .axi_arready        (axi_arready),
        // r
        .axi_rid            (axi_rid),
        .axi_rdata          (axi_rdata),
        .axi_rresp          (axi_rresp),
        .axi_rlast          (axi_rlast),
        .axi_rvalid         (axi_rvalid),
        .axi_rready         (axi_rready),
    /* ********* AXI Master Interface ********* */

    /* ********* ICache Interface ********* */
        // AXI Read
        .inst_rd_req        (inst_rd_req),
        .inst_rd_type       (inst_rd_type),
        .inst_rd_addr       (inst_rd_addr),
        .inst_rd_rdy        (inst_rd_rdy),
        .inst_ret_valid     (inst_ret_valid),
        .inst_ret_last      (inst_ret_last),
        .inst_ret_data      (inst_ret_data),
        // AXI Write
        .inst_wr_req        (inst_wr_req),
        .inst_wr_type       (inst_wr_type),
        .inst_wr_addr       (inst_wr_addr),
        .inst_wr_wstrb      (inst_wr_wstrb),
        .inst_wr_data       (inst_wr_data),
        .inst_wr_rdy        (inst_wr_rdy),
        // Fault
        .inst_read_fault    (inst_read_fault),
        .inst_write_fault   (inst_write_fault),
    /* ********* ICache Interface ********* */

    /* ********* DCache Interface ********* */
        // AXI Read
        .data_rd_req        (data_rd_req),
        .data_rd_type       (data_rd_type),
        .data_rd_addr       (data_rd_addr),
        .data_rd_rdy        (data_rd_rdy),
        .data_ret_valid     (data_ret_valid),
        .data_ret_last      (data_ret_last),
        .data_ret_data      (data_ret_data),
        // AXI Write
        .data_wr_req        (data_wr_req),
        .data_wr_type       (data_wr_type),
        .data_wr_addr       (data_wr_addr),
        .data_wr_wstrb      (data_wr_wstrb),
        .data_wr_data       (data_wr_data),
        .data_wr_rdy        (data_wr_rdy),
        // Fault
        .data_read_fault    (data_read_fault),
        .data_write_fault   (data_write_fault)
    /* ********* DCache Interface ********* */
    );

/* -------------------------------- Bridge -------------------------------- */

/* -------------------------------- Cache -------------------------------- */
    logic           ibus_req;
    logic           ibus_op;
    logic [2:0]     ibus_size;
    logic [7:0]     ibus_mask;
    logic [31:0]    ibus_addr;
    logic [63:0]    ibus_wdata;
    logic [63:0]    ibus_rdata;
    logic           ibus_addr_ok;
    logic           ibus_data_ok;
    logic           ibus_uncache;
    logic           ibus_cache_miss;
    logic           ibus_load_fault;
    logic           ibus_store_fault;

    logic           dbus_req;
    logic           dbus_op;
    logic [2:0]     dbus_size;
    logic [7:0]     dbus_mask;
    logic [31:0]    dbus_addr;
    logic [63:0]    dbus_wdata;
    logic [63:0]    dbus_rdata;
    logic           dbus_addr_ok;
    logic           dbus_data_ok;
    logic           dbus_uncache;
    logic           dbus_cache_miss;
    logic           dbus_load_fault;
    logic           dbus_store_fault;

    Cache icache (
        .clock          (clock),
        .reset          (reset),

    /* ********* Cache <-> CPU ********* */
        .req_valid      (ibus_req),
        .op             (ibus_op),
        .tag            (ibus_addr[31:11]),
        .index          (ibus_addr[10:4]),
        .offset         (ibus_addr[3:0]),
        .wstrb          (ibus_mask),
        .wdata          (ibus_wdata),
        .addr_ok        (ibus_addr_ok),
        .data_ok        (ibus_data_ok),
        .rdata          (ibus_rdata),
        .size           (ibus_size),
        .uncache        (ibus_uncache),
        .cache_miss     (ibus_cache_miss),
        .load_fault     (ibus_load_fault),
        .store_fault    (ibus_store_fault),
    /* ********* Cache <-> CPU ********* */

    /* ********* Cache <-> AXI ********* */
        // AXI Read
        .rd_req         (inst_rd_req),
        .rd_type        (inst_rd_type),
        .rd_addr        (inst_rd_addr),
        .rd_rdy         (inst_rd_rdy),
        .ret_valid      (inst_ret_valid),
        .ret_last       (inst_ret_last),
        .ret_data       (inst_ret_data),
        // AXI Write
        .wr_req         (inst_wr_req),
        .wr_type        (inst_wr_type),
        .wr_addr        (inst_wr_addr),
        .wr_wstrb       (inst_wr_wstrb),
        .wr_data        (inst_wr_data),
        .wr_rdy         (inst_wr_rdy),
        // Fault
        .read_fault     (inst_read_fault),
        .write_fault    (inst_write_fault)
    /* ********* Cache <-> AXI ********* */
    );

    Cache dcache (
        .clock          (clock),
        .reset          (reset),

    /* ********* Cache <-> CPU ********* */
        .req_valid      (dbus_req),
        .op             (dbus_op),
        .tag            (dbus_addr[31:11]),
        .index          (dbus_addr[10:4]),
        .offset         (dbus_addr[3:0]),
        .wstrb          (dbus_mask),
        .wdata          (dbus_wdata),
        .addr_ok        (dbus_addr_ok),
        .data_ok        (dbus_data_ok),
        .rdata          (dbus_rdata),
        .size           (dbus_size),
        .uncache        (dbus_uncache),
        .cache_miss     (dbus_cache_miss),
        .load_fault     (dbus_load_fault),
        .store_fault    (dbus_store_fault),
    /* ********* Cache <-> CPU ********* */

    /* ********* Cache <-> AXI ********* */
        // AXI Read
        .rd_req         (data_rd_req),
        .rd_type        (data_rd_type),
        .rd_addr        (data_rd_addr),
        .rd_rdy         (data_rd_rdy),
        .ret_valid      (data_ret_valid),
        .ret_last       (data_ret_last),
        .ret_data       (data_ret_data),
        // AXI Write
        .wr_req         (data_wr_req),
        .wr_type        (data_wr_type),
        .wr_addr        (data_wr_addr),
        .wr_wstrb       (data_wr_wstrb),
        .wr_data        (data_wr_data),
        .wr_rdy         (data_wr_rdy),
        // Fault
        .read_fault     (data_read_fault),
        .write_fault    (data_write_fault)
    /* ********* Cache <-> AXI ********* */
    );
/* -------------------------------- Cache -------------------------------- */

/* -------------------------------- Core -------------------------------- */
    Core core (
        .clock              (clock),
        .reset              (reset),
        // Interrupts
        .clint_msi          (msi), // from CLINT
        .clint_mti          (mti), // from CLINT
        // for debug
        .debug_wb_pc        (debug_wb_pc),
        .debug_wb_valid     (debug_wb_valid),
        // Commit
        .icache_miss_count  (icache_miss_count),
        .dcache_miss_count  (dcache_miss_count),
        .commit_inst_count  (commit_inst_count),
        .mmio_inst_count    (mmio_inst_count),
        .mem_inst_count     (mem_inst_count),
        .commit_valid       (commit_valid),
        .commit_pc          (commit_pc),
        .commit_inst        (commit_inst),
        .commit_skip_ref    (commit_skip_ref),

        // InstBus interface
        .ibus_req           (ibus_req),
        .ibus_op            (ibus_op),
        .ibus_size          (ibus_size),
        .ibus_mask          (ibus_mask),
        .ibus_addr          (ibus_addr),
        .ibus_wdata         (ibus_wdata),
        .ibus_rdata         (ibus_rdata),
        .ibus_addr_ok       (ibus_addr_ok),
        .ibus_data_ok       (ibus_data_ok),
        .ibus_uncache       (ibus_uncache),
        .ibus_cache_miss    (ibus_cache_miss),
        .ibus_load_fault    (ibus_load_fault),
        .ibus_store_fault   (ibus_store_fault),

        // DataBus interface
        .dbus_req           (dbus_req),
        .dbus_op            (dbus_op),
        .dbus_size          (dbus_size),
        .dbus_mask          (dbus_mask),
        .dbus_addr          (dbus_addr),
        .dbus_wdata         (dbus_wdata),
        .dbus_rdata         (dbus_rdata),
        .dbus_addr_ok       (dbus_addr_ok),
        .dbus_data_ok       (dbus_data_ok),
        .dbus_uncache       (dbus_uncache),
        .dbus_cache_miss    (dbus_cache_miss),
        .dbus_load_fault    (dbus_load_fault),
        .dbus_store_fault   (dbus_store_fault)
    );
/* -------------------------------- Core -------------------------------- */


endmodule
